package com.zz.client.handle.defaults;

import com.zz.client.config.ChannelCache;
import com.zz.common.annotation.Executor;
import com.zz.common.config.Constants;
import com.zz.common.entity.ClientConfig;
import com.zz.common.entity.Information;
import com.zz.common.enums.MessageType;
import com.zz.common.handle.executor.AbstractMessageExecutor;
import com.zz.common.protocol.DefaultProtocol;
import com.zz.common.utils.ObjectUtil;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;

/**
 * 连接处理
 *
 * @Author: zz
 */
@Slf4j
@Executor(msgType = MessageType.TYPE_CONNECT)
public class ConnectExecutor extends AbstractMessageExecutor {

    private Bootstrap bootstrap;
    private Bootstrap localBootstrap;

    @Override
    public void execute(Information information) {
        DefaultProtocol protocol = (DefaultProtocol) information.getProtocolMsg();
        ClientConfig config = protocol.getMeta().getConfig();
        if (ObjectUtil.isNull(config) || !config.isValid()) {
            log.error("client connect error, config is null");
            return;
        }
        this.bootstrap = information.getBootstrap();
        this.localBootstrap = information.getLocalBootstrap();
        // 从队列中获取代理channel，如果没有则创建
        ChannelCache.bindChannel(bootstrap, information.getContext(), config, channel -> {
            if (ObjectUtil.isNull(channel)) {
                log.error("client connect error, channel is null");
                fail(information.getContext(), protocol, "服务器连接异常");
                return;
            }
            // 获取server连接成功，创建本地连接
            success(information.getContext(), protocol, config, channel);
        });

    }

    /**
     * 获取server连接成功后获取本地连接
     * @param context
     * @param protocol
     * @param config
     * @param salveChannel
     */
    private void success(ChannelHandlerContext context, DefaultProtocol protocol, ClientConfig config, Channel salveChannel) {
        localBootstrap.connect(config.getConfigIp(), ObjectUtil.toInt(config.getConfigPort())).addListener((ChannelFutureListener) future -> {
            if (future.isSuccess()) {
                // 绑定server和本地连接
                future.channel().attr(Constants.Attributes.META).set(protocol.getMeta());
                future.channel().attr(Constants.Attributes.SERVER_CHANNEL).set(salveChannel);
                salveChannel.attr(Constants.Attributes.LOCAL_CHANNEL).set(future.channel());
                sendSuccessMessage(salveChannel, protocol);
            } else {
                // 将获取到的server连接放入队列中并发送失败消息
                ChannelCache.addSalveServerChannel(salveChannel);
                fail(context, protocol, "本地连接异常");
            }
        });
    }

    /**
     * 发送成功连接消息
     * @param salveChannel
     * @param protocol
     */
    private void sendSuccessMessage(Channel salveChannel, DefaultProtocol protocol) {
        DefaultProtocol.Builder builder = DefaultProtocol.builder().type(MessageType.TYPE_CONNECT)
                .serializationType(protocol.getSerializationType())
                .serialNumber(protocol.getSerialNumber())
                .header(Constants.Strings.SUCCESS)
                .meta(protocol.getMeta());

        salveChannel.writeAndFlush(builder.build());
    }

    /**
     * 发送失败连接消息
     * @param context
     * @param protocol
     * @param message
     */
    private void fail(ChannelHandlerContext context, DefaultProtocol protocol, String message) {
        protocol.setType(MessageType.CONNECT_FAIR.getMark());
        protocol.getMeta().setErrorInfo(message);
        context.writeAndFlush(protocol);
    }




}
